package com.wyt.common.jsch;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName JschConnection
 * @Description: 远程连接工具类
 * @Author wangyongtao
 * @Date 2023/6/17 20:02
 * @Version 1.0
 **/
public class JschConnection implements Closeable {

    private static Logger logger = LoggerFactory.getLogger(JschConnection.class);

    private int timeout = 60 * 60 * 1000;

    private Session session = null;

    private ChannelExec channelExec = null;
    private ChannelSftp channelSftp4 = null;

    private BufferedReader inputStreamRead = null;
    private BufferedReader errInputstreamRead = null;

    public JschConnection(String ip, int port, String user, String pwd, int timeout) throws Exception {
        logger.info("建立远程连接ip={},port={},user={},pwd={},timeout={}", ip, port, user, pwd, timeout);
        JSch jsch = new JSch();
        session = jsch.getSession(user, ip, port);
        session.setPassword(pwd);
        if (timeout > 0) this.timeout = timeout * 1000;
        session.setTimeout(this.timeout);
        this.session.setConfig("uSeTauth.gssapi-with-mic", "no");
        this.session.setConfig("StrictHostKeyChecking", "no");
        this.session.connect();
        logger.info("远程连接建立成功！");
    }


    /**
     * 执行同步命令
     *
     * @return 返回map集合包含三个键值对：
     * 分别为捕获到的正常执行日志(key为runLog)，和捕获到的错误日志(key为errlog)，以及命令执行后的退出码(key为resultKey)
     */
    public Map<String, String> execsynccmd(String cmd) throws Exception {
        logger.info("远程会话同步执行命令：\n{}", cmd);
        StringBuilder runLog = new StringBuilder();
        StringBuilder errlog = new StringBuilder();
        Map<String, String> resultMap = new HashMap<>();

        channelExec = (ChannelExec) session.openChannel("exec");
        for (String s : cmd.split(";")) channelExec.setCommand(s);
        channelExec.connect();
        inputStreamRead = new BufferedReader(new InputStreamReader(channelExec.getInputStream()));
        errInputstreamRead = new BufferedReader(new InputStreamReader(channelExec.getErrStream()));

        String Line = null;
        while ((Line = inputStreamRead.readLine()) != null) runLog.append(Line).append("\n");
        while ((Line = errInputstreamRead.readLine()) != null) errlog.append(Line).append("\n");

        int resultKey = channelExec.getExitStatus();
        resultMap.put("resultKey", resultKey + "");
        resultMap.put("runLog", runLog.toString());
        resultMap.put("errLog", errlog.toString());
        logger.info("命令同步执行完成，返回码：[{}] \n执行日志为：\n{}\n错误日志为：\n{}", resultKey, runLog, errlog);
        return resultMap;
    }

    /**
     * 执行异步命令
     * 异步命令不接受返回，命令发出后就会关闭连接
     */
    public void execAsyncCmd(String cmd) throws Exception {
        logger.info("远程会话异步执行命令：\n{}", cmd);
        channelExec = (ChannelExec) session.openChannel("exec");
        for (String s : cmd.split(";")) channelExec.setCommand(s);
        channelExec.connect();
        logger.info("命令异步发送完");
    }

    @Override
    public void close() throws IOException {
        if (inputStreamRead != null) inputStreamRead.close();
        if (errInputstreamRead != null) errInputstreamRead.close();
        if (channelExec != null) channelExec.disconnect();
        if (session != null) session.disconnect();
    }
}